ExpandablePropertyDrawer.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using UnityEngine;
  2. using UnityEditor;
  3. namespace ExternPropertyAttributes.Editor
  4. {
  5. [CustomPropertyDrawer(typeof(ExpandableAttribute))]
  6. public class ExpandablePropertyDrawer : PropertyDrawerBase
  7. {
  8. protected override float GetPropertyHeight_Internal(SerializedProperty property, GUIContent label)
  9. {
  10. System.Type propertyType = PropertyUtility.GetPropertyType(property);
  11. if (typeof(ScriptableObject).IsAssignableFrom(propertyType))
  12. {
  13. ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject;
  14. if (scriptableObject == null)
  15. {
  16. return GetPropertyHeight(property);
  17. }
  18. if (property.isExpanded)
  19. {
  20. using (SerializedObject serializedObject = new SerializedObject(scriptableObject))
  21. {
  22. float totalHeight = EditorGUIUtility.singleLineHeight;
  23. using (var iterator = serializedObject.GetIterator())
  24. {
  25. if (iterator.NextVisible(true))
  26. {
  27. do
  28. {
  29. SerializedProperty childProperty = serializedObject.FindProperty(iterator.name);
  30. if (childProperty.name.Equals("m_Script", System.StringComparison.Ordinal))
  31. {
  32. continue;
  33. }
  34. bool visible = PropertyUtility.IsVisible(childProperty);
  35. if (!visible)
  36. {
  37. continue;
  38. }
  39. float height = GetPropertyHeight(childProperty);
  40. totalHeight += height;
  41. }
  42. while (iterator.NextVisible(false));
  43. }
  44. }
  45. totalHeight += EditorGUIUtility.standardVerticalSpacing;
  46. return totalHeight;
  47. }
  48. }
  49. else
  50. {
  51. return GetPropertyHeight(property);
  52. }
  53. }
  54. else
  55. {
  56. return GetPropertyHeight(property) + GetHelpBoxHeight();
  57. }
  58. }
  59. protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label)
  60. {
  61. EditorGUI.BeginProperty(rect, label, property);
  62. System.Type propertyType = PropertyUtility.GetPropertyType(property);
  63. if (typeof(ScriptableObject).IsAssignableFrom(propertyType))
  64. {
  65. ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject;
  66. if (scriptableObject == null)
  67. {
  68. EditorGUI.PropertyField(rect, property, label, false);
  69. }
  70. else
  71. {
  72. // Draw a foldout
  73. Rect foldoutRect = new Rect()
  74. {
  75. x = rect.x,
  76. y = rect.y,
  77. width = EditorGUIUtility.labelWidth,
  78. height = EditorGUIUtility.singleLineHeight
  79. };
  80. property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label, toggleOnLabelClick: true);
  81. // Draw the scriptable object field
  82. float indentLength = ExternalCustomEditorGUI.GetIndentLength(rect);
  83. float labelWidth = EditorGUIUtility.labelWidth - indentLength + ExternalCustomEditorGUI.HorizontalSpacing;
  84. Rect propertyRect = new Rect()
  85. {
  86. x = rect.x + labelWidth,
  87. y = rect.y,
  88. width = rect.width - labelWidth,
  89. height = EditorGUIUtility.singleLineHeight
  90. };
  91. EditorGUI.BeginChangeCheck();
  92. property.objectReferenceValue = EditorGUI.ObjectField(propertyRect, GUIContent.none, property.objectReferenceValue, propertyType, false);
  93. if (EditorGUI.EndChangeCheck())
  94. {
  95. property.serializedObject.ApplyModifiedProperties();
  96. }
  97. // Draw the child properties
  98. if (property.isExpanded)
  99. {
  100. DrawChildProperties(rect, property);
  101. }
  102. }
  103. }
  104. else
  105. {
  106. string message = $"{typeof(ExpandableAttribute).Name} can only be used on scriptable objects";
  107. DrawDefaultPropertyAndHelpBox(rect, property, message, MessageType.Warning);
  108. }
  109. EditorGUI.EndProperty();
  110. }
  111. private void DrawChildProperties(Rect rect, SerializedProperty property)
  112. {
  113. ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject;
  114. if (scriptableObject == null)
  115. {
  116. return;
  117. }
  118. Rect boxRect = new Rect()
  119. {
  120. x = 0.0f,
  121. y = rect.y + EditorGUIUtility.singleLineHeight,
  122. width = rect.width * 2.0f,
  123. height = rect.height - EditorGUIUtility.singleLineHeight
  124. };
  125. GUI.Box(boxRect, GUIContent.none);
  126. using (new EditorGUI.IndentLevelScope())
  127. {
  128. EditorGUI.BeginChangeCheck();
  129. SerializedObject serializedObject = new SerializedObject(scriptableObject);
  130. using (var iterator = serializedObject.GetIterator())
  131. {
  132. float yOffset = EditorGUIUtility.singleLineHeight;
  133. if (iterator.NextVisible(true))
  134. {
  135. do
  136. {
  137. SerializedProperty childProperty = serializedObject.FindProperty(iterator.name);
  138. if (childProperty.name.Equals("m_Script", System.StringComparison.Ordinal))
  139. {
  140. continue;
  141. }
  142. bool visible = PropertyUtility.IsVisible(childProperty);
  143. if (!visible)
  144. {
  145. continue;
  146. }
  147. float childHeight = GetPropertyHeight(childProperty);
  148. Rect childRect = new Rect()
  149. {
  150. x = rect.x,
  151. y = rect.y + yOffset,
  152. width = rect.width,
  153. height = childHeight
  154. };
  155. ExternalCustomEditorGUI.PropertyField(childRect, childProperty, true);
  156. yOffset += childHeight;
  157. }
  158. while (iterator.NextVisible(false));
  159. }
  160. }
  161. if (EditorGUI.EndChangeCheck())
  162. {
  163. serializedObject.ApplyModifiedProperties();
  164. }
  165. }
  166. }
  167. }
  168. }